#include "StdAfx.h"
#include "IDT.h"
#include "console.h"

static void __declspec(naked) isr_empty()
{
	_asm pushad;

	putline ("ISR was called!");

    _asm
	{		
        popad									
        iretd									
    }											
}

static void __declspec(naked) isr_GP_handler()
{
	putline ("General Protection Fault");

	halt();
}

IDT::IDT()
{
	for (int i = 0; i < IDT_ENTRIES_COUNT; i++)
	{
		SetSys32ISRHandler(i, isr_empty);
	}

	SetSys32ISRHandler(13, isr_GP_handler);

	m_isActive  = false;
}

IDT::~IDT()
{
	if (m_isActive)
	{
		Deactivate();
	}
}


#ifdef DEBUG
extern "C"
{
	extern void breakpoint ();
}
#endif

void IDT::Activate()
{
	if (!m_isActive)
	{
		m_isActive = true;

#pragma pack (push, 1)
		struct
		{
			WORD   size;
			LPVOID pTable;
		} m_idt;
#pragma pack (pop, 1)
		
		m_idt.size   = sizeof(m_entries);
		m_idt.pTable = m_entries;

		__asm
		{
			cli

			lidt m_idt

			sti
		};

#ifdef DEBUG
		breakpoint ();
#endif
	}
}

void IDT::Deactivate()
{
	if (m_isActive)
	{
		m_isActive = false;

		__asm
		{
			cli
		};
	}
}


#define ISR_ATTRIB(gate_type, storage_seg, dpl, present)	\
	(gate_type & 0x7)  | ((storage_seg & 0x1) << 4) |		\
	((dpl & 0x3) << 5) | ((storage_seg & 0x1) << 7)

#define _32_task_gate	0x5		// 80386 32 bit Task gate
#define _16_isr_gate	0x6		// 80286 16-bit interrupt gate
#define _16_trap_gate	0x7		// 80286 16-bit trap gate
#define _32_isr_gate	0xE		// 80386 32-bit interrupt gate
#define _32_trap_gate	0xF		// 80386 32-bit trap gate

void IDT::SetISRHandler(BYTE id, PISR pIsr, BYTE attrib)
{
	DWORD      isr_addr = (DWORD)pIsr;
	PIDT_ENTRY pEntry   = m_entries + id;

	pEntry->zero		= 0;
	pEntry->selector	= 0x0008;
	pEntry->offset_1	= (isr_addr & 0x0000ffff);
	pEntry->offset_2	= ((isr_addr >> 16) & 0x0000ffff);

	pEntry->type_attr	= attrib;
}

void IDT::SetSys32ISRHandler(BYTE id, PISR pIsr)
{
	SetISRHandler(id, pIsr, ISR_ATTRIB(_32_isr_gate, 0, 0, 1));
}
